package com.ceair.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.ceair.entity.model.UserInfo;
import com.ceair.util.UserInfoUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import java.time.LocalDateTime;

/**
 * @author wangbaohai
 * @ClassName MybatisPlusConfig
 * @description: MybatisPlus分页插件
 * @date 2024年11月19日
 * @version: 1.0.0
 */
@Configuration
@EnableTransactionManagement //开启事务
@RequiredArgsConstructor
@Slf4j
public class MybatisPlusConfig {

    private final UserInfoUtils userInfoUtils;

    /**
     * 配置并创建一个 MybatisPlusInterceptor 的 Bean 实例。
     * 该拦截器用于增强 MyBatis-Plus 的功能，例如分页支持。
     *
     * @return MybatisPlusInterceptor 返回一个配置好的 MybatisPlusInterceptor 实例，
     *         包含分页拦截器以支持 MySQL 数据库的分页查询。
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        // 创建 MybatisPlusInterceptor 实例，作为核心拦截器容器
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

        // 添加分页拦截器，指定数据库类型为 MySQL
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));

        return interceptor;
    }

    /**
     * 创建一个MetaObjectHandler的Bean，用于处理实体对象的自动填充逻辑。
     * 该处理器在插入和更新操作时，会自动填充一些公共字段，如创建者、修改者、创建时间、修改时间等。
     *
     * @return MetaObjectHandler 返回一个实现了MetaObjectHandler接口的匿名类实例，用于处理自动填充逻辑。
     */
    @Bean
    public MetaObjectHandler metaObjectHandler() {
        return new MetaObjectHandler() {
            /**
             * 在插入操作时自动填充字段。
             * 该方法会从认证信息中获取当前用户信息，并填充以下字段：
             * - deleted: 设置为0，表示未删除
             * - creatorId: 设置为当前用户的ID
             * - creatorName: 设置为当前用户的账号
             * - createTime: 设置为当前时间
             * - modifierId: 设置为当前用户的ID
             * - modifierName: 设置为当前用户的账号
             * - modifyTime: 设置为当前时间
             *
             * @param metaObject 元对象，表示待填充的实体对象
             */
            @Override
            public void insertFill(MetaObject metaObject) {
                UserInfo userInfo = getUserInfoSafely();

                // 填充创建者和修改者字段
                fillCreatorFields(metaObject, userInfo);
                fillModifierFields(metaObject, userInfo);
            }

            /**
             * 在更新操作时自动填充字段。
             * 该方法会从认证信息中获取当前用户信息，并填充以下字段：
             * - modifierId: 设置为当前用户的ID
             * - modifierName: 设置为当前用户的账号
             * - modifyTime: 设置为当前时间
             *
             * @param metaObject 元对象，表示待填充的实体对象
             */
            @Override
            public void updateFill(MetaObject metaObject) {
                UserInfo userInfo = getUserInfoSafely();

                // 填充修改者字段
                fillModifierFields(metaObject, userInfo);
            }

            /**
             * 安全地获取用户信息，避免空指针异常。
             *
             * @return UserInfo 当前用户信息，如果为空则构建一个系统用户。
             */
            private UserInfo getUserInfoSafely() {
                UserInfo userInfo = userInfoUtils.getUserInfoFromAuthentication();
                if (userInfo == null) {
                    log.warn("无法获取用户信息，使用系统用户进行自动填充操作！");
                    userInfo = new UserInfo();
                    userInfo.setId(0L);
                    userInfo.setAccount("系统自动操作");
                }
                return userInfo;
            }

            /**
             * 填充创建者相关字段。
             *
             * @param metaObject 元对象
             * @param userInfo   用户信息
             */
            private void fillCreatorFields(MetaObject metaObject, UserInfo userInfo) {
                this.strictInsertFill(metaObject, "recordVersion", () -> 0, Integer.class);
                this.strictInsertFill(metaObject, "deleted", () -> false, Boolean.class);
                this.strictInsertFill(metaObject, "sort", () -> 0, Integer.class);
                this.strictInsertFill(metaObject, "creatorId", userInfo::getId, Long.class);
                this.strictInsertFill(metaObject, "creatorName", userInfo::getAccount, String.class);
                this.strictInsertFill(metaObject, "createTime", LocalDateTime::now, LocalDateTime.class);
            }

            /**
             * 填充修改者相关字段。
             *
             * @param metaObject 元对象
             * @param userInfo   用户信息
             */
            private void fillModifierFields(MetaObject metaObject, UserInfo userInfo) {
                this.strictUpdateFill(metaObject, "modifierId", userInfo::getId, Long.class);
                this.strictUpdateFill(metaObject, "modifierName", userInfo::getAccount, String.class);
                this.strictUpdateFill(metaObject, "modifyTime", LocalDateTime::now, LocalDateTime.class);
            }
        };
    }
}